/**
 * by sunny 2015-12-08
 */
package uf.audit.util;

import java.util.List;

import org.apache.log4j.Logger;

import uf.audit.controller.UFBaseController;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.jfinal.config.Routes;
import com.jfinal.kit.StrKit;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class AuditRoutes extends Routes {
	private boolean autoScan = true;

	private List<Class<? extends UFBaseController>> excludeClasses = Lists
			.newArrayList();
	private boolean includeAllJarsInLib;
	private List<String> includeJars = Lists.newArrayList();

	protected final Logger log = Logger.getLogger(getClass());

	private String suffix = "Controller";

	public AuditRoutes autoScan(boolean autoScan) {
		this.autoScan = autoScan;
		return this;
	}

	public AuditRoutes addExcludeClasses(
			Class<? extends UFBaseController>[] clazzes) {
		if (clazzes != null) {
			for (Class clazz : clazzes) {
				this.excludeClasses.add(clazz);
			}
		}
		return this;
	}

	public AuditRoutes addExcludeClasses(
			List<Class<? extends UFBaseController>> clazzes) {
		this.excludeClasses.addAll(clazzes);
		return this;
	}

	public AuditRoutes addJars(String... jars) {
		if (jars != null) {
			for (String jar : jars) {
				this.includeJars.add(jar);
			}
		}
		return this;
	}

	public void config() {
		List<Class<? extends UFBaseController>> controllerClasses = null;
		try {
			controllerClasses = ClassSearcher.of(UFBaseController.class)
					.includeAllJarsInLib(includeAllJarsInLib)
					.injars(includeJars).search();
		} catch (Exception e) {
			e.printStackTrace();
		}
		Controller controllerAnnotation = null;
		for (Class controller : controllerClasses) {
			if (excludeClasses.contains(controller)) {
				continue;
			}
			controllerAnnotation = (Controller) controller
					.getAnnotation(Controller.class);
			if (controllerAnnotation == null) {
				if (!autoScan) {
					continue;
				}
				this.add(controllerKey(controller), controller);
				log.debug("routes.add(" + controllerKey(controller) + ", "
						+ controller.getName() + ")");
			} else if (StrKit.isBlank(controllerAnnotation.view())) {
				this.add(controllerAnnotation.url(), controller);
				log.debug("routes.add(" + controllerAnnotation.url() + ", "
						+ controller.getName() + ")");
			} else {
				this.add(controllerAnnotation.url(), controller,
						controllerAnnotation.view());
				log.debug("routes.add(" + controllerAnnotation.url() + ", "
						+ controller + "," + controllerAnnotation.view() + ")");
			}
		}
	}

	private String controllerKey(Class<Controller> clazz) {
		Preconditions
				.checkArgument(
						clazz.getSimpleName().endsWith(this.suffix),
						clazz.getName()
								+ " is not annotated with @ControllerBind and not end with "
								+ this.suffix);

		String controllerKey = "/"
				+ StrKit.firstCharToLowerCase(clazz.getSimpleName());
		controllerKey = controllerKey.substring(0,
				controllerKey.indexOf(this.suffix));
		return controllerKey;
	}

	public AuditRoutes includeAllJarsInLib(boolean includeAllJarsInLib) {
		this.includeAllJarsInLib = includeAllJarsInLib;
		return this;
	}

	public AuditRoutes suffix(String suffix) {
		this.suffix = suffix;
		return this;
	}
}
